package com.bk.bands;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Stack;

import javax.imageio.ImageIO;

import com.bk.bands.model.Border;
import com.bk.bands.model.Style;
import com.bk.bands.print.Paper;
import com.bk.bands.runtime.PrintException;

public class PaperImpl implements Paper
{
   private int paperDPI;
   private Dimension paperSizeMM10;
   private BufferedImage paperImage;
   private Graphics2D paperGraphics;
   Stack<Point> viewPortStack = new Stack<Point>();

   public PaperImpl(int paperDPI, Dimension paperSizeMM10)
   {
      this.paperDPI = paperDPI;
      this.paperSizeMM10 = paperSizeMM10;
   }

   private BufferedImage createPaperImage(Dimension pixelSize)
   {
      return  new BufferedImage(pixelSize.width,pixelSize.height, BufferedImage.TYPE_INT_RGB);//BufferedImage.TYPE_BYTE_GRAY);
   }

   public Point popViewPort()
   {
      return viewPortStack.pop();
   }

   public void pushViewPort(Point viewPort)
   {
      viewPortStack.push(new Point(viewPort));
   }

   private int toPaperDots(int mm10)
   {
      return toDots(mm10,paperDPI);
   }

   private int toDots(int mm10,int DPI)
   {
      final double inchTimes100 = 2.54*100;
      double inches = mm10/inchTimes100;
      Double pixels = inches*DPI;
      long rounded = Math.round(pixels);
//      int iii =  pixels.intValue();
      return (int)rounded;//(mm10*DPI)/254;
   }

   private Graphics2D getPaperGraphics() throws PrintException
   {

      if(paperImage == null)
      {
         if(paperDPI < 100)
         {
            throw new PrintException("Min. DPI is 100");
         }

         if(paperSizeMM10.height <= 0 || paperSizeMM10.width <= 0)
         {
            throw new PrintException("Invalid paper size");
         }

         paperImage = createPaperImage(new Dimension(toPaperDots(paperSizeMM10.width)+1,toPaperDots(paperSizeMM10.height)+1));

      }
      if(paperGraphics == null)
      {
         paperGraphics = paperImage.createGraphics();
         paperGraphics.setColor(Color.WHITE);
         paperGraphics.fillRect(0,0,paperImage.getWidth(),paperImage.getHeight());

      }

      return paperGraphics;
   }

   private Stroke createStroke(int pixelLineWidth)
   {
      return new BasicStroke(pixelLineWidth);
   }

   private Point calculateViewPort()
   {
      Point viewPort = new Point(0,0);
      for(Point newOrigin : viewPortStack)
      {
         viewPort.translate(newOrigin.x,newOrigin.y);
      }
      return viewPort;
   }

   public void drawRectangle(Rectangle rect, Border border) throws PrintException
   {
      Graphics2D grx = getPaperGraphics();

      Point viewPortOrigin = calculateViewPort();
//      Point paperViewPotOrigin = new Point(toPaperDots(viewPortOrigin.x),toPaperDots(viewPortOrigin.y));
      AffineTransform transform = new AffineTransform();
      transform.setToTranslation(toPaperDots(viewPortOrigin.x),toPaperDots(viewPortOrigin.y));
      grx.setTransform(transform);
      Stroke oldStroke = grx.getStroke();
      grx.setStroke(createStroke(border.getLineWidth()));
      grx.setColor(border.getLineColor());
//      grx.drawRect(toPaperDots(rect.x)+paperViewPotOrigin.x,toPaperDots(rect.y)+paperViewPotOrigin.y,
//                   toPaperDots(rect.width)+paperViewPotOrigin.x,toPaperDots(rect.height)+paperViewPotOrigin.y);

      grx.drawRect(toPaperDots(rect.x),toPaperDots(rect.y),
                   toPaperDots(rect.width),toPaperDots(rect.height));
      grx.setStroke(oldStroke);
   }



   public void drawText(String text, Style style, Rectangle rect, Border border) throws PrintException
   {
      Graphics2D grx = getPaperGraphics();
      if(border != null)
      {
         drawRectangle(rect,border);
      }

      grx.drawString(text,toPaperDots(rect.x),toPaperDots(rect.y+20));



   }

   public void drawCircle(Point center, int radius, Border border) throws PrintException
   {
      Graphics2D grx = getPaperGraphics();

   }

   public void save(OutputStream imageStream) throws IOException
   {
      ImageIO.write(paperImage, "bmp", imageStream);
   }
}